`timescale 1ns/1ns
//behavioral moore ssm with four outputs
module moore_4_outputs_case (clk, x1, x2, x3, y, z1, z2, z3, z4);
input clk, x1, x2, x3; //define inputs and outputs
output [2:0] y;
output z1, z2, z3, z4;
reg [2:0] y, next_state; //variables are reg in always
//assign state codes
parameter state_a = 3'b101, //parameter defines a constant
          state_b = 3'b110,
          state_c = 3'b011,
          state_d = 3'b000,
          state_e = 3'b001;

//define outputs
assign {z1, z2, z3, z4} = (y == state_a) ? 4'b0000 : 
                          (y == state_b) ? 4'b1000 : 
                          (y == state_c) ? 4'b0100 : 
                          (y == state_d) ? 4'b0010 : 
                          (y == state_e) ? 4'b0001 : 4'b0000;

//set next state
always @ (posedge clk)
    y <= next_state;

//determine next state
always @ (*) begin
    case (y)
    state_a: 
        if(~x1 & ~x3) next_state = state_b;
        else if(~x1 & x3) next_state = state_c;
        else if(x1 & ~x2 & ~x3) next_state = state_d;
        else if(x1 &  x2 &  x3) next_state = state_e;
        else next_state = state_a;
    default:
        next_state = state_a;
    endcase
end
endmodule


//test bench for moore ssm with four outputs
module moore_4_outputs_case_tb;
//inputs are reg for test bench
//outputs are wire for test bench
reg clk, x1, x2, x3;
wire [2:0] y;
wire z1, z2, z3, z4;

//display variables
initial
    $monitor ("x1 x2 x3 = %b%b%b, state = %b, z1 z2 z3 z4 = %b%b%b%b",
               x1, x2, x3, y, z1, z2, z3, z4);

//define clock
initial begin
    clk = 1'b0;
    forever #10 clk = ~clk;
end

//apply input vectors
initial begin
    x1 = 1'b0;
    x2 = 1'b0;
    x3 = 1'b0;
    @ (posedge clk) //go to state_b (110)
    @ (posedge clk) //go to state_a (101)
    x1 = 1'b0;
    x2 = 1'b1;
    x3 = 1'b1;
    @ (posedge clk) //go to state_c (011)
    @ (posedge clk) //go to state_a (101)
    x1 = 1'b1;
    x2 = 1'b0;
    x3 = 1'b0;
    @ (posedge clk) //go to state_d (000)
    @ (posedge clk) //go to state_a (101)
    x1 = 1'b1;
    x2 = 1'b1;
    x3 = 1'b1;
    @ (posedge clk) //go to state_e (001)
    @ (posedge clk) //go to state_a (101)
    x1 = 1'b1;
    x2 = 1'b0;
    x3 = 1'b1;
    @ (posedge clk) //go to state_a (101)
    x1 = 1'b1;
    x2 = 1'b1;
    x3 = 1'b0;
    @ (posedge clk) //go to state_a (101)
    #10 $finish;
end

//instantiate the module into the test bench
moore_4_outputs_case inst1 (clk, x1, x2, x3, y, z1, z2, z3, z4);

/*iverilog */
initial begin
    $dumpfile("moore_4_outputs_case_tb.vcd"); //生成的 vcd 文件名称
    $dumpvars(0, moore_4_outputs_case_tb); //测试模块名称
end
/*iverilog */

endmodule